package edu.um.automata;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

import edu.um.token.TokenKind;

public class TransitionTable {
  private final Map<String, Map<String, Collection<Transition>>> table;

  public TransitionTable() {
    table = new HashMap<String, Map<String, Collection<Transition>>>();
  }

  public void addTransition(int from, int to, TokenKind input) throws Exception {
    addTransition(from, to, input, null);
  }

  public void addTransition(int from, int to, TokenKind input, StackSymbol pop)
      throws Exception {
    addTransition(from, to, input, pop, null);
  }

  public void addTransition(int from, int to, TokenKind input, StackSymbol pop,
      StackSymbol push1) throws Exception {
    addTransition(from, to, input, pop, push1, null);
  }

  public void addTransition(int from, int to, TokenKind input, StackSymbol pop,
      StackSymbol push1, StackSymbol push2) throws Exception {
    addTransition(String.valueOf(from),
        new Transition(input, pop, push1, push2), String.valueOf(to));
  }

  public void addTransition(String stateFrom, Transition theTransition,
      String stateTo) throws Exception {
    if (theTransition == null) {
      throw new IllegalArgumentException("The transition can not be null");
    }
    addStateIfNecessary(stateFrom);
    addStateIfNecessary(stateTo);
    Map<String, Collection<Transition>> file = table.get(stateFrom);
    for (String state : file.keySet()) {
      Collection<Transition> transitions = file.get(state);
      for (Transition transition : transitions) {
        if (transition.equals(theTransition)) {
          throw new Exception("Duplicated transaction for state " + stateFrom
              + ": " + transition.getTokenKind() + "::"
              + transition.getStackSymbolReceived());
        }
      }
      if (state.equals(stateTo)) {
        transitions.add(theTransition);
      }
    }
  }

  public Collection<Transition> getTransitions(String stateFrom,
      String stateTo) {
    Map<String, Collection<Transition>> file = table.get(stateFrom);
    if (file == null) {
      return null;
    }
    return file.get(stateTo);
  }

  public Map<String, Collection<Transition>> getFile(String stateFrom) {
    return table.get(stateFrom);
  }

  public void addStateIfNecessary(String state) {
    if (table.get(state) == null) {
      Map<String, Collection<Transition>> newFile = new HashMap<String, Collection<Transition>>();
      newFile.put(state, new ArrayList<Transition>());
      for (String stateFrom : table.keySet()) {
        newFile.put(stateFrom, new ArrayList<Transition>());
        table.get(stateFrom).put(state, new ArrayList<Transition>());
      }
      table.put(state, newFile);
    }
  }
}
